/**
 * 文件说明:多线程为相机处理过程,子线程进行数据处理
 * 简单不校验发包收包
 * 安全串口解包和发包协议
 * 0xA5 0xA6 2字节 帧起始 包长度 1字节 数据 n字节 2字节 CRC16 校验
 */
#include <iostream>
#include <errno.h>
#include <cstring>
#include <thread>
#include <vector>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>


// 共享队列、锁和条件变量
//std::queue<std::vector<char>> dataQueue;
std::mutex mtx;
//std::condition_variable cv;
//bool finished = false; // 结束标志

//串口配置
void configureSerialPort(int fd, int baudRate, int dataBits, int stopBits, char parity);
//自定义发包函数
void sendSerialPort(const int& _serialPort,const void* message,const uint8_t message_size);
//初始化串口
int initserial(int& _serialPort)
{
    //初始化串口并获取文件描述符保存到fd变量里
    //if ((_serialPort = open("/dev/serial0", O_RDWR | O_NOCTTY | O_NDELAY |O_NONBLOCK)) < 0) //允许读写,非终端控制进程,非阻塞
    if ((_serialPort = open("/dev/serial0", O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) < 0) //允许读写,非终端控制进程,非阻塞
    {
     std::cerr << "Unable to open serial device" << std::endl;
     return 1 ;
    }
 
 
    // 设置串口参数
    configureSerialPort(_serialPort, B115200, 8, 1, 'N');


    // 清空输入缓冲区  Line Control 
    tcflush(_serialPort, TCIFLUSH);
    tcflush(_serialPort, TCOFLUSH);
    tcflush(_serialPort, TCOON); //TCOON 重启输出
    return 0;
}

void receiveThread(const int& fd);
void ProcessThread(const int& fd);

int main() {
      //初始化串口  
      int serialPort;
      int res = initserial(serialPort);
      std::cout << "initserial_res:" << res << std::endl;
      
      std::thread receiver(receiveThread, serialPort);
      std::thread processer(ProcessThread, serialPort);
      
      //等待接收线程结束
      //receiver.join();
      //将接收线程分离
      receiver.detach();
      processer.join();
      
      

}
constexpr int bufferSize = 256; // 缓冲区大小
//char buffer[bufferSize]= {};
//共享缓冲区，需要加锁
char buffer_shared[bufferSize] = {};
bool receive_finished = false;
//memset(buffer, 0, bufferSize); // 初始化缓冲区
void ProcessThread(const int& _serialPort)
{
  while(1)
  {
    {
      std::lock_guard<std::mutex> lock(mtx);
      if(receive_finished == true)
      {
        receive_finished = false;
        std::cout << "ProcessThread:"  << buffer_shared << std::endl;
        //const char* message = "Hello, STM32!";
        const uint8_t message[] = "Hello, STM32!";
        std::cout << "Debug:message_size:" << sizeof(message) << std::endl;
        sendSerialPort(_serialPort,message,sizeof(message) - 1);
        //int tx_n = write(_serialPort, message, strlen(message));
        //std::cout << "raspi_send:" << message << ",true size:" << tx_n << std::endl;
      }  
    }
  }

}


//注意不可重入
uint32_t Verify_CRC16_Check_Sum(uint8_t *pchMessage, uint32_t dwLength);
typedef struct
{
    uint8_t  length;
    uint8_t buffer[bufferSize]; 
    uint8_t all_data[bufferSize + 5];
    uint16_t CRC;
    bool CRC_success;
}RX_Buffer_T;
RX_Buffer_T RX_Buffer;
//接收信息状态机
typedef enum
{
    MyPack_Frame_SOF,
    MyPack_Frame_DataLength,
    MyPack_Frame_DATA,
    MyPack_Frame_CRC16,
    MyPack_FrameStatusLength
} MyPackRX_Status_T;
#define MYPACK_FRAMEHEADER_SOF1 0xA5
#define MYPACK_FRAMEHEADER_SOF2 0xA6
//单字节解包
void Receive_Unpacked(uint8_t& rx_byte)
{
  static MyPackRX_Status_T PackRX_Status = MyPack_Frame_SOF;
  static uint8_t CRC16_count = 0;
  static uint8_t SOF_count = 0;
  static uint8_t DataLenth_count = 0;
  
  switch(PackRX_Status)
  {
      case MyPack_Frame_SOF:
      {
          if(rx_byte == MYPACK_FRAMEHEADER_SOF1 && SOF_count == 0)
          {
            RX_Buffer.all_data[0] = rx_byte;
            SOF_count = 1;   
            PackRX_Status = MyPack_Frame_SOF;
          }
          else if(rx_byte == MYPACK_FRAMEHEADER_SOF2 && SOF_count == 1)				//起始字节
          {
            RX_Buffer.all_data[1] = rx_byte; 
            SOF_count = 0;
            RX_Buffer.length = 0; 
            PackRX_Status = MyPack_Frame_DataLength;	
          }
          else
          {
            SOF_count = 0; 
            PackRX_Status = MyPack_Frame_SOF;
          }
          break;
      }
      /***/
      case MyPack_Frame_DataLength:
      {
        RX_Buffer.length = rx_byte;
        RX_Buffer.all_data[2] = rx_byte;
        PackRX_Status = MyPack_Frame_DATA;

        DataLenth_count = 0;
        memset(RX_Buffer.buffer,0,sizeof(RX_Buffer.buffer));
        
        break;
      }
      case MyPack_Frame_DATA:
      {
        RX_Buffer.buffer[DataLenth_count] = rx_byte;
        RX_Buffer.all_data[3 + DataLenth_count] = rx_byte;
        DataLenth_count++;
        if(DataLenth_count >= RX_Buffer.length)
        {
            CRC16_count = 0;
            RX_Buffer.CRC &=~(uint16_t)0xFFFF;
            PackRX_Status = MyPack_Frame_CRC16;
        }
        break;
      }
      case MyPack_Frame_CRC16:
      {
        RX_Buffer.CRC_success = 0;
        if(CRC16_count == 0)
        {
            CRC16_count = 1;
            RX_Buffer.CRC |= (uint16_t)rx_byte;//树莓派STM32 little endian
            RX_Buffer.all_data[3 + DataLenth_count] = rx_byte;
        }
        else if(CRC16_count == 1)
        {
            RX_Buffer.all_data[4 + DataLenth_count] = rx_byte;
            RX_Buffer.CRC |= (((uint16_t)rx_byte) << 8);//树莓派STM32 little endian CRC 人类可读
            PackRX_Status = MyPack_Frame_SOF;
            if(Verify_CRC16_Check_Sum(RX_Buffer.all_data,RX_Buffer.length+5))
            {
                //加锁
                std::lock_guard<std::mutex> lock(mtx);
                RX_Buffer.CRC_success = 1;
                memcpy(buffer_shared,RX_Buffer.buffer,RX_Buffer.length);	
                receive_finished = true;					
            }
            
        }
        else
        {
            PackRX_Status = MyPack_Frame_SOF;
        }
        break;
      }
      default:break;

  }
}
//增加互斥锁
void receiveThread(const int& fd){
    static int index = 0; // 当前缓冲区索引
    int serialPort = fd;
      //std::cout << "Debug:read" << std::endl;
    static char buffer_data[50];
    static int receive_flag = 0;
    while(1)
    {
      memset(buffer_data,0,sizeof(buffer_data));
      const int bytes_read = read(serialPort, buffer_data, sizeof(buffer_data));
      std::cout << "Debug:read_complete,byte_read:"<< bytes_read << std::endl;
      int bytes_read_temp = bytes_read;
      int num = 100;
      
      //处理数据
      while(bytes_read_temp > 0 && num > 0) {
          //std::lock_guard<std::mutex> lock(mtx);
          //std::cout << "Debug:data" << std::endl;
          //std::cout<< "Debug:current_byte:" <<bytes_read_temp << std::endl;
          uint8_t data = buffer_data[bytes_read - bytes_read_temp]; // 读取一个字符
          //.std::cout << "Debug:ASCII:"<<(int)data << std::endl;
          // 如果接收到换行符（假设STM32以换行符结束数据）
          /*
          if(data == '\r')
          {
            //std::cout << "r:"<<(int)data << std::endl;
            receive_flag = 1;
            bytes_read_temp = bytes_read_temp - 1;
            num--;
            continue;
          }
          else if (data == '\n' && receive_flag == 1) {
              std::lock_guard<std::mutex> lock(mtx);//对数据buff加锁
              //std::cout << "n:"<<(int)data << std::endl;
              buffer[index] = '\0'; // 添加字符串结束符
              //std::cout << "Debug:receive_data:" << buffer << std::endl;
              strcpy(buffer_shared,buffer);
              receive_finished = true;
              index = 0; // 重置缓冲区索引
              memset(buffer, 0, bufferSize); // 清空缓冲区
          } 
          else{//数据未结束
              //std::lock_guard<std::mutex> lock(mtx);//对数据buff加锁
              if (index < bufferSize - 1) { // 防止缓冲区溢出
                  buffer[index++] = data; // 存储数据到缓冲区
              } 
              else {
                  std::cerr << "Debug:buff full:" << buffer << std::endl;
                  index = 0; // 重置缓冲区索引
                  memset(buffer, 0, bufferSize); // 清空缓冲区
                  //测试发送
                  //const char *message = "Hello, STM32!";
                  //write(serialPort, message, strlen(message));
                  //std::cout << "raspi_send" << buffer << std::endl;
              }
          }
          
          receive_flag  = 0;
          */
          Receive_Unpacked(data);
          bytes_read_temp = bytes_read_temp - 1;
          num--;
      }
      if(num == 0)
        std::cout << "num未知错误" << std::endl;
      if(bytes_read_temp != 0)
        std::cout << "已提前检测到结束" << std::endl;
        
        
      usleep(500000);
    }
  
}

void configureSerialPort(int fd, int baudRate, int dataBits, int stopBits, char parity) {
    struct termios options;
    
    /*
        struct termios
        {
          unsigned short c_iflag;      //输入模式标志
          unsigned short c_oflag;      //输出模式标志
          unsigned short c_cflag;      //控制模式标志
          unsigned short c_lflag;      //本地模式标志
          unsigned char c_line;        //线路规则
          unsigned char c_cc[NCC];     //控制字
        };
        c_iflag字段:IGNPAR 忽略帧错误和奇偶校验错误 INPCK
    */

    // 获取当前串口的设置
    if (tcgetattr(fd, &options) != 0) {
        std::cerr << "Error getting serial port attributes" << std::endl;
        return;
    }
    //不忽略换行和回车
    //options.c_iflag &=~INLCR;
    //options.c_iflag &=~IGNCR;
    //options.c_iflag &=~ICRNL;
    options.c_iflag &= ~(ICRNL | INLCR | IGNCR);//ICRNL 映射输入上的 CR 到 NL;INLCR 将 NL 映射到输入上的 CR;IGNCR 忽略回车符
    

    // 设置波特率
    cfsetispeed(&options, baudRate);
    cfsetospeed(&options, baudRate);

    // 设置数据位（通常为 8 位）
    options.c_cflag &= ~CSIZE;  // 清除数据位设置
    switch (dataBits) {
        case 5: options.c_cflag |= CS5; break;
        case 6: options.c_cflag |= CS6; break;
        case 7: options.c_cflag |= CS7; break;
        case 8: options.c_cflag |= CS8; break;
        default:
            std::cerr << "Invalid data bits" << std::endl;
            return;
    }

    // 设置停止位
    if (stopBits == 1) {
        options.c_cflag &= ~CSTOPB;  // 1 位停止位
    } else if (stopBits == 2) {
        options.c_cflag |= CSTOPB;   // 2 位停止位
    } else {
        std::cerr << "Invalid stop bits" << std::endl;
        return;
    }

    // 设置校验位
    if (parity == 'N') {
        options.c_cflag &= ~PARENB;  // 无校验
        options.c_iflag &= ~INPCK;   // 不启用输入校验
    } else if (parity == 'O') {
        options.c_cflag |= PARENB;   // 开启校验
        options.c_cflag |= PARODD;   // 奇校验
        options.c_iflag |= INPCK;    // 启用输入校验
    } else if (parity == 'E') {
        options.c_cflag |= PARENB;   // 开启校验
        options.c_cflag &= ~PARODD;  // 偶校验
        options.c_iflag |= INPCK;    // 启用输入校验
    } else {
        std::cerr << "Invalid parity option" << std::endl;
        return;
    }

    // 使能串口配置并关闭硬件流控制
    options.c_cflag |= (CLOCAL | CREAD);  // 启用接收并忽略调制解调器控制线
    options.c_cflag &= ~CRTSCTS;          // 禁用硬件流控制
    options.c_iflag &= ~(IXON | IXOFF | IXANY);// 禁用软件流控制
    //options.c_iflag |= IXON | IXOFF | IXANY;
    //软件流控制:options.c_iflag |= IXON | IXOFF | IXANY

    // 设置串口为原始模式
    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    options.c_oflag &= ~OPOST;

    // 设置数据传输时的字符大小，接收超时等(no blocked模式无意义)
    options.c_cc[VMIN] = 0;    // 1,至少读取 1 字节数据
    options.c_cc[VTIME] = 0;   // 5,超时 0.5 秒

    // 应用配置
    if (tcsetattr(fd, TCSANOW, &options) != 0) {
        std::cerr << "Error setting serial port attributes" << std::endl;
        return;
    }
}
void Append_CRC16_Check_Sum(unsigned char *pchMessage, unsigned int dwLength);
void sendSerialPort(const int& _serialPort,const void* message,const uint8_t message_size)
{
  /*自定义协议 */ 
  uint8_t message_send[message_size + 5];
  message_send[0] = MYPACK_FRAMEHEADER_SOF1;
  message_send[1] = MYPACK_FRAMEHEADER_SOF2;
  message_send[2] = message_size;
  memcpy(message_send + 3,message,message_size);
  Append_CRC16_Check_Sum(message_send,message_size + 5);
//   message_send[message_size] = '\r';
//   message_send[message_size + 1] = '\n';
  int write_res = write(_serialPort, message_send, sizeof(message_send));
  std::cout << "Debug:SendSize:" <<  sizeof(message_send) << ",true_size:" << write_res << std::endl;
}


/**
 * @defgroup CRC_Communication_function 
 * CRC校验和大小端模式转换函数
*/
/**
 * @addtogroup CRC_Communication_function
 * @{
*/

//将Unit16_t类型高低位取反
void Uint16ToChar(uint16_t input, uint8_t *array)
{
    *(array)        = (uint8_t)(input & 0x00ff);
    *(array + 1)    = (uint8_t)((input >> 8) & 0x00ff);
}

//CRC 校验代码示例
//crc8 generator polynomial:G(x)=x8+x5+x4+1
const unsigned char CRC8_INIT = 0xff;
const unsigned char CRC8_TAB[256] =
{
    0x00, 0x5e, 0xbc, 0xe2, 0x61, 0x3f, 0xdd, 0x83, 0xc2, 0x9c, 0x7e, 0x20, 0xa3, 0xfd, 0x1f, 0x41,
    0x9d, 0xc3, 0x21, 0x7f, 0xfc, 0xa2, 0x40, 0x1e, 0x5f, 0x01, 0xe3, 0xbd, 0x3e, 0x60, 0x82, 0xdc,
    0x23, 0x7d, 0x9f, 0xc1, 0x42, 0x1c, 0xfe, 0xa0, 0xe1, 0xbf, 0x5d, 0x03, 0x80, 0xde, 0x3c, 0x62,
    0xbe, 0xe0, 0x02, 0x5c, 0xdf, 0x81, 0x63, 0x3d, 0x7c, 0x22, 0xc0, 0x9e, 0x1d, 0x43, 0xa1, 0xff,
    0x46, 0x18, 0xfa, 0xa4, 0x27, 0x79, 0x9b, 0xc5, 0x84, 0xda, 0x38, 0x66, 0xe5, 0xbb, 0x59, 0x07,
    0xdb, 0x85, 0x67, 0x39, 0xba, 0xe4, 0x06, 0x58, 0x19, 0x47, 0xa5, 0xfb, 0x78, 0x26, 0xc4, 0x9a,
    0x65, 0x3b, 0xd9, 0x87, 0x04, 0x5a, 0xb8, 0xe6, 0xa7, 0xf9, 0x1b, 0x45, 0xc6, 0x98, 0x7a, 0x24,
    0xf8, 0xa6, 0x44, 0x1a, 0x99, 0xc7, 0x25, 0x7b, 0x3a, 0x64, 0x86, 0xd8, 0x5b, 0x05, 0xe7, 0xb9,
    0x8c, 0xd2, 0x30, 0x6e, 0xed, 0xb3, 0x51, 0x0f, 0x4e, 0x10, 0xf2, 0xac, 0x2f, 0x71, 0x93, 0xcd,
    0x11, 0x4f, 0xad, 0xf3, 0x70, 0x2e, 0xcc, 0x92, 0xd3, 0x8d, 0x6f, 0x31, 0xb2, 0xec, 0x0e, 0x50,
    0xaf, 0xf1, 0x13, 0x4d, 0xce, 0x90, 0x72, 0x2c, 0x6d, 0x33, 0xd1, 0x8f, 0x0c, 0x52, 0xb0, 0xee,
    0x32, 0x6c, 0x8e, 0xd0, 0x53, 0x0d, 0xef, 0xb1, 0xf0, 0xae, 0x4c, 0x12, 0x91, 0xcf, 0x2d, 0x73,
    0xca, 0x94, 0x76, 0x28, 0xab, 0xf5, 0x17, 0x49, 0x08, 0x56, 0xb4, 0xea, 0x69, 0x37, 0xd5, 0x8b,
    0x57, 0x09, 0xeb, 0xb5, 0x36, 0x68, 0x8a, 0xd4, 0x95, 0xcb, 0x29, 0x77, 0xf4, 0xaa, 0x48, 0x16,
    0xe9, 0xb7, 0x55, 0x0b, 0x88, 0xd6, 0x34, 0x6a, 0x2b, 0x75, 0x97, 0xc9, 0x4a, 0x14, 0xf6, 0xa8,
    0x74, 0x2a, 0xc8, 0x96, 0x15, 0x4b, 0xa9, 0xf7, 0xb6, 0xe8, 0x0a, 0x54, 0xd7, 0x89, 0x6b, 0x35,
};
static unsigned char Get_CRC8_Check_Sum(unsigned char *pchMessage,unsigned int dwLength,unsigned char ucCRC8)
{
    unsigned char ucIndex;
    while (dwLength--)
    {
        ucIndex = ucCRC8^(*pchMessage++);
        ucCRC8 = CRC8_TAB[ucIndex];
    }
    return(ucCRC8);
}
/*
** Descriptions: CRC8 Verify function
** Input: Data to Verify,Stream length = Data + checksum
** Output: True or False (CRC Verify Result)
*/
uint8_t Verify_CRC8_Check_Sum(unsigned char *pchMessage, unsigned int dwLength)
//static uint8_t Verify_CRC8_Check_Sum(unsigned char *pchMessage, unsigned int dwLength)
{
    unsigned char ucExpected = 0;
    if ((pchMessage == 0) || (dwLength <= 2)) return 0;
    ucExpected = Get_CRC8_Check_Sum (pchMessage, dwLength-1, CRC8_INIT);
    return ( ucExpected == pchMessage[dwLength-1] );
}
/*
** Descriptions: append CRC8 to the end of data
** Input: Data to CRC and append,Stream length = Data + checksum
** Output: True or False (CRC Verify Result)
*/
void Append_CRC8_Check_Sum(unsigned char *pchMessage, unsigned int dwLength)
{
    unsigned char ucCRC = 0;
    if ((pchMessage == 0) || (dwLength <= 2)) return;
    ucCRC = Get_CRC8_Check_Sum ( (unsigned char *)pchMessage, dwLength-1, CRC8_INIT);
    pchMessage[dwLength-1] = ucCRC;
}
uint16_t CRC_INIT = 0xffff;
const uint16_t wCRC_Table[256] =
{
    0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
    0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
    0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
    0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
    0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
    0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
    0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
    0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
    0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
    0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
    0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
    0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
    0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
    0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
    0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
    0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
    0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
    0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
    0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
    0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
    0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
    0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
    0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
    0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
    0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
    0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
    0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
    0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
    0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
    0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
    0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
    0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};
/*
** Descriptions: CRC16 checksum function
** Input: Data to check,Stream length, initialized checksum
** Output: CRC checksum
*/
static uint16_t Get_CRC16_Check_Sum(uint8_t *pchMessage,uint32_t dwLength,uint16_t wCRC)
{
    uint8_t chData;
    if (pchMessage == NULL)
    {
        return 0xFFFF;
    }
    while(dwLength--)
    {
        chData = *pchMessage++;
        (wCRC) = ((uint16_t)(wCRC) >> 8) ^ wCRC_Table[((uint16_t)(wCRC) ^ (uint16_t)(chData)) & 0x00ff];
    }
    return wCRC;
}
/*
** Descriptions: CRC16 Verify function
** Input: Data to Verify,Stream length = Data + checksum
** Output: True or False (CRC Verify Result)
*/
//static uint32_t Verify_CRC16_Check_Sum(uint8_t *pchMessage, uint32_t dwLength)
uint32_t Verify_CRC16_Check_Sum(uint8_t *pchMessage, uint32_t dwLength)
{
    uint16_t wExpected = 0;
    if ((pchMessage == NULL) || (dwLength <= 2))
    {
        return 0;
    }
    wExpected = Get_CRC16_Check_Sum ( pchMessage, dwLength - 2, CRC_INIT);
    return ((wExpected & 0xff) == pchMessage[dwLength - 2] && ((wExpected >> 8) & 0xff) == pchMessage[dwLength - 1]);
	}
/*
** Descriptions: append CRC16 to the end of data
** Input: Data to CRC and append,Stream length = Data + checksum
** Output: True or False (CRC Verify Result)
*/
void Append_CRC16_Check_Sum(uint8_t * pchMessage,uint32_t dwLength)
{
    uint16_t wCRC = 0;
    if ((pchMessage == NULL) || (dwLength <= 2))
    {
        return;
    }
    wCRC = Get_CRC16_Check_Sum ( (uint8_t *)pchMessage, dwLength-2, CRC_INIT );
    pchMessage[dwLength-2] = (uint8_t)(wCRC & 0x00ff);
    pchMessage[dwLength-1] = (uint8_t)((wCRC >> 8)& 0x00ff);
}

/**
 * @}
 */